﻿using System;
using Bookvar.ObjectModel;
using Bookvar.ObjectModel.Actions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Bookvar.UnitTests.ObjectModel.Actions
{
    /// <summary>
    /// Tests for the <see cref="AddTopicAction"/> class.
    /// </summary>
    [TestClass]
    public class AddTopicActionTests : CommonActionTests
    {
        /// <summary>
        /// Creates a <see cref="AddTopicAction"/> for common action tests.
        /// </summary>
        protected override IAction CreateAction()
        {
            return new AddTopicAction { Topic = new Topic(), Parent = new Topic() };
        }

        [TestMethod]
        public void CanCreateNew()
        {
            var addTopicAction = new AddTopicAction();
            Assert.IsNotNull( addTopicAction );
        }

        [TestMethod]
        [ExpectedException( typeof ( ArgumentNullException ) )]
        public void New_WithNullNewTopic_Throws()
        {
            var addTopicAction = new AddTopicAction( null );
            Assert.IsNotNull( addTopicAction );
        }

        [TestMethod]
        [ExpectedException( typeof ( ArgumentNullException ) )]
        public void NewTopic_SetToNull_Throws()
        {
            new AddTopicAction { Topic = null };
        }

        [TestMethod]
        [ExpectedException( typeof ( ArgumentNullException ) )]
        public void Parent_SetToNull_Throws()
        {
            new AddTopicAction { Parent = null };
        }

        [TestMethod]
        [ExpectedException( typeof ( InvalidOperationException ) )]
        public void Execute_WithNotSetNewTopic_Throws()
        {
            new AddTopicAction { Parent = new Topic() }.Execute();
        }

        [TestMethod]
        [ExpectedException( typeof ( InvalidOperationException ) )]
        public void Execute_WithNotSetParent_Throws()
        {
            new AddTopicAction { Topic = new Topic() }.Execute();
        }

        [TestMethod]
        public void Execute_AddsTheNewTopicToTheParentSubtopics()
        {
            var newTopic = new Topic();
            var parent = new Topic();

            new AddTopicAction { Topic = newTopic, Parent = parent }.Execute();

            CollectionAssert.Contains( parent.SubTopics, newTopic );
        }

        [TestMethod]
        public void Execute_WithNotSetInsertIndex_AddsTheNewTopicToTheEndOfTheParentSubtopics()
        {
            var newTopic = new Topic();
            var parent = new Topic();
            parent.SubTopics.Add( new Topic() );

            new AddTopicAction { Topic = newTopic, Parent = parent }.Execute();

            Assert.IsTrue( parent.SubTopics.IndexOf( newTopic ) == 1 );
        }

        [TestMethod]
        public void Execute_WithInsertIndex_AddsTheNewTopicAtTheSpecifiedIndex()
        {
            var newTopic = new Topic();
            var parent = new Topic();
            parent.SubTopics.Add( new Topic() );
            parent.SubTopics.Add( new Topic() );

            new AddTopicAction { Topic = newTopic, Parent = parent, InsertIndex = 1 }.Execute();

            Assert.IsTrue( parent.SubTopics.IndexOf( newTopic ) == 1 );
        }

        [TestMethod]
        public void Undo_RemovesTheTopicFromTheParent()
        {
            var newTopic = new Topic();
            var parent = new Topic();

            var addTopicAction = new AddTopicAction { Topic = newTopic, Parent = parent };
            addTopicAction.Execute();
            addTopicAction.Undo();

            CollectionAssert.DoesNotContain( parent.SubTopics, newTopic );
        }
    }
}